/*
 * Copyright 2006 - Chris Maki
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.agoracms.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;

@Entity
@Table(name="topic")
@NamedQueries({
	@NamedQuery(name="topic.findByForumAndSubject", query="select t from Topic t where t.forum = ?1 AND t.subject = ?2"),
	@NamedQuery(name="topic.findRootPosts", query="select p from Topic t join t.posts p where t = ?1 AND p.parent is null")
})
public class Topic extends ModelBase {

    private static final long serialVersionUID = 5415142549335146747L;
      
    @Lob
    protected String content;
    
    @Column(name="topic_subject")
    protected String subject;
    
    protected Integer views = 0;

    protected Integer replies = 0;

    @Column(name="topic_order")
    protected Integer topicOrder;
    
    @Column(name="post_cout")
    protected Integer postCount;
    
    @Enumerated(EnumType.ORDINAL)
    FTPType type = FTPType.NORMAL;
    
    @OneToMany(targetEntity=Post.class, mappedBy="topic",fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE})
    @OrderBy("type asc, dateUpdated desc")
    Set<Post> posts = new HashSet<Post>();
    
     // TopLinkFix
     // @ManyToOne(fetch=FetchType.LAZY, optional=false)
    @ManyToOne(optional=false)
    Forum forum;
    
    public static Topic createdBasicTopic(String subject, String content) {
    	Topic t = new Topic();
    	t.setContent(content);
    	t.setSubject(subject);

    	return t;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }   
  
    public Set<Post> getPosts() {
        return posts;
    }
    public void setPosts(Set<Post> posts) {
        this.posts = posts;
    }
    /**
     * Clients of agoraBB must use Forum.addPostToTopic to add a post to a topic. 
     * 
     * @param post
     * @return
     * @see Forum#addPostToTopic(Post, Topic)
     */
    protected boolean addPost(Post post) {
    	boolean successful = posts.add(post);
    	if (successful) {
			incrementPostCount();
			// manually manage the relationship
			post.setTopic(this);
		}
        return successful;
    }
    private void incrementPostCount() {
    	int count = getPostCount();
    	setPostCount(++count);
		
	}
	public boolean removePost(Post post) {
    	post.setTopic(null);
        return posts.remove(post);
    }

    public Integer getReplies() {
        return replies;
    }
    public void setReplies(Integer replies) {
        this.replies = replies;
    }
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public FTPType getType() {
        return type;
    }
    public void setType(FTPType type) {
        this.type = type;
    }
    public Integer getViews() {
        return views;
    }
    public void setViews(Integer views) {
        this.views = views;
    }
    public Integer getOrder() {
        return topicOrder;
    }
    public void setOrder(Integer order) {
        this.topicOrder = order;
    }
	public Forum getForum() {
		return forum;
	}
	/**
	 * Managest the Topic to Forum relationships, sets the forum for this topic
	 * and adds this instance to the list of topics in the form.
	 * 
	 * @param forum
	 */
	public void setForum(Forum forum) {
		this.forum = forum;
	}
	public Integer getPostCount() {
		if (postCount == null) {
			postCount = new Integer(0);
		}
		return postCount;
	}
	public void setPostCount(Integer postCount) {
		this.postCount = postCount;
	}
	@Override
	public int hashCode() {
		final int PRIME = 31;
		int result = 1;
		result = PRIME * result + ((forum == null) ? 0 : forum.hashCode());
		result = PRIME * result + ((content == null) ? 0 : content.hashCode());
		result = PRIME * result + ((subject == null) ? 0 : subject.hashCode());

		return result;
	}
	/**
	 * Since a topic does not require that you have a unique subject or content,
	 * it is a little difficult to create a full-proof equals method, however,
	 * all Topics are required to have a forum. This equals method will use the
	 * forum relationship as part of equality
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Topic))
			return false;
		final Topic other = (Topic) obj;
		
		if (forum == null) {
			if (other.getForum() != null)
				return false;
		} else if (!forum.equals(other.getForum()))
			return false;
		
		if (content == null) {
			if (other.getContent() != null)
				return false;
		} else if (!content.equals(other.getContent()))
			return false;
		if (subject == null) {
			if (other.getSubject() != null)
				return false;
		} else if (!subject.equals(other.getSubject()))
			return false;
		return true;
	}
	
	
}
